#include <iostream>
#include <fstream>

//#define _STDCALL_SUPPORTED
//#define _M_IX86
#include "../glut.h"

#include "Sphere.h"
#include "Plane.h"
#include "Tracer.h"
#include "Scene.h"
#include "Camera.h"
#include "SceneParser.h"
#include "RenderTarget.h"

Tracer * tracer;
Scene * scene;
RT_Memory * rtMem;
int width, height;

int keysUp = 0;
int keysDown = 0;
int keysRight = 0;
int keysLeft = 0;

int keysRotLeft = 0;
int keysRotRight = 0;



void idleFunc()
{
	static int oldTime = glutGet(GLUT_ELAPSED_TIME);
	int newTime = glutGet(GLUT_ELAPSED_TIME);
	float deltaTimeMs = newTime - oldTime;
	oldTime = newTime;

	if (keysUp)
	{
		scene->GetEditableCamera().MoveForward(deltaTimeMs * keysUp);
		keysUp = 0;
	}
	if (keysDown)
	{
		scene->GetEditableCamera().MoveBackward(deltaTimeMs * keysDown);
		keysDown = 0;
	}
	if (keysRight)
	{
		scene->GetEditableCamera().MoveRight(deltaTimeMs * keysRight);
		keysRight = 0;
	}
	if (keysLeft)
	{
		scene->GetEditableCamera().MoveLeft(deltaTimeMs * keysLeft);
		keysLeft = 0;
	}
	if (keysRotLeft)
	{
		scene->GetEditableCamera().RotateY(-deltaTimeMs * keysRotLeft);
		keysRotLeft = 0;
	}
	if (keysRotRight)
	{
		scene->GetEditableCamera().RotateY(deltaTimeMs * keysRotRight);
		keysRotRight = 0;
	}

	glutPostRedisplay();
}

__int64 gFrameSumTimes = 0;
int gFrameNum = 0;

void renderScene()
{
	unsigned __int64 startTime, endTime;
	startTime = __rdtsc();

	tracer->Render(*rtMem, *scene, false);

	endTime = __rdtsc();
	gFrameSumTimes += (endTime - startTime) / 1000;
	gFrameNum++;
	

	//glBindTexture(GL_TEXTURE_2D, 1);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB,
			GL_UNSIGNED_BYTE, rtMem->GetPixels());

	glBegin(GL_QUADS);
		//glColor3ub(rtMem->GetPixels()->R, rtMem->GetPixels()->G, rtMem->GetPixels()->B);
		glTexCoord2f(0.0f, 0.0f);
		glVertex2f(-1.0, -1.0);
		glTexCoord2f(1.0f, 0.0f);
		glVertex2f(1.0, -1.0);
		glTexCoord2f(1.0f, 1.0f);
		glVertex2f(1.0, 1.0);
		glTexCoord2f(0.0f, 1.0f);
		glVertex2f(-1.0, 1.0);
	glEnd();

	glFlush();
	glutSwapBuffers();
}

void cleanup()
{
	std::ofstream logfile("LOGS.txt", std::ios::out);
	if(logfile.is_open())
	{
		logfile << "Average frame computing time: " << (gFrameSumTimes / gFrameNum) << "\n";
	}

	delete rtMem;
	delete tracer;
	delete scene;

	//glutInit_ATEXIT_HACK
}

void processKeys(int key, int x, int y)
{
	if (key == GLUT_KEY_UP) keysUp++;
	if (key == GLUT_KEY_DOWN) keysDown++;
	if (key == GLUT_KEY_RIGHT) keysRight++;
	if (key == GLUT_KEY_LEFT) keysLeft++;
	if (key == GLUT_KEY_INSERT) keysRotLeft++;
	if (key == GLUT_KEY_HOME) keysRotRight++;
	if (key == GLUT_KEY_F1) cleanup();
}



int main(int argc, char **argv)
{
	SceneParser sceneParser;
	scene = sceneParser.ParseFromFile("scene.txt");

	width = sceneParser.GetParsedWidth();
	height = sceneParser.GetParsedHeight();

	tracer = new Tracer;
	rtMem = new RT_Memory(width, height);

	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);

	glutInitWindowPosition(100, 100);
	glutInitWindowSize(width, height);
	glutCreateWindow("Trayracer");

	GLuint texname;

	glEnable(GL_TEXTURE_2D);
	glGenTextures(1, &texname);
	glBindTexture(GL_TEXTURE_2D, texname);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

	glutDisplayFunc(renderScene);
	glutSpecialFunc(processKeys);
	glutIdleFunc(idleFunc);

	atexit(cleanup);

	glutMainLoop();


	return 0;
}



//int main(void)
//{
//	SceneParser sceneParser;
//	Scene * scene = sceneParser.ParseFromFile("scene.txt");
//
//	RT_BMP bmp(sceneParser.GetParsedWidth(), sceneParser.GetParsedHeight());
//
//	Tracer rt;
//
//	cout << "Computing started...\n";
//
//	unsigned __int64 startTime, endTime;
//	startTime = __rdtsc();
//	rt.Render(bmp, *scene, sceneParser.GetParsedShowProgressOption());
//	endTime = __rdtsc();
//
//	cout << "\nCycles to compute (in thousands): " << (endTime - startTime) / 1000
//					<< "\n";
//
//	bmp.WriteToFile("img32.bmp");
//
//	getchar();
//
//	delete scene;
//
//	return 0;
//}
//
//
